package com.hylanda.util.http;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.hylanda.pb.service.common.ConstantHelper;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;

/**
 * 
 * @author zhangy
 * @E-mail:blackoon88@gmail.com
 * @qq:846579287
 * @version 创建时间：2018年1月19日 下午2:39:36 note
 */
@Component
public class OkHttpUtils {
	public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
	public static final String MULTIPART_FORM_DATA = "multipart/form-data";
	public static final MediaType JSON = MediaType
			.parse("application/json; charset=utf-8");
	public static final String GET = "GET";
	public static final String POST = "POST";
	public static final String PUT = "PUT";
	public static final String PATCH = "PATCH";
	public static final String HEAD = "HEAD";
	public static final String DELETE = "DELETE";

	private final AtomicReference<OkHttpClient> okHttpClientAtomicReference = new AtomicReference<>();

	public OkHttpUtils() {
		OkHttpClient okHttpClient = new OkHttpClient();
		// Set timeouts
		okHttpClient.setConnectTimeout(30, TimeUnit.SECONDS);
		okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
		okHttpClient.setWriteTimeout(30, TimeUnit.SECONDS);
		// Set whether to follow redirects
		okHttpClient.setFollowRedirects(true);
		okHttpClientAtomicReference.set(okHttpClient);
	}

	public String httpRequestWithContent(String method, String urlstr,
			Map<String, String> headerPropertys, String contentType,
			String content) {
		return httpRequest(method, urlstr, headerPropertys, contentType,content, null);
	}

	public String httpRequest(String method, String urlstr,
			Map<String, String> headerPropertys, String contentType,
			String content, RequestBody withRequestBody) {
		OkHttpClient okHttpClient = okHttpClientAtomicReference.get();
		try {
			final URL url = new URL(urlstr);
			Request httpRequest = configureRequest(method, url,
					headerPropertys, contentType, content, withRequestBody);
			Response responseHttp = okHttpClient.newCall(httpRequest).execute();

			// output the raw response headers (DEBUG level only)
			// logResponse(logger, url, responseHttp);
			// store the status code and message
			int statusCode = responseHttp.code();
			// String statusMessage = responseHttp.message();

			if (statusCode == 0) {
				throw new IllegalStateException("Status code unknown, connection hasn't been attempted.");
			}
			ResponseBody responseBody = responseHttp.body();
			try {
				return responseBody.string();
			} catch (Exception e) {
				return String.valueOf(statusCode);
			}
		} catch (final Exception e) {
			e.printStackTrace();
		}
		return "500";
	}

	private Request configureRequest(String method, URL url,
			Map<String, String> headerPropertys, String contentType,
			String content, RequestBody withRequestBody) {
		Request.Builder requestBuilder = new Request.Builder();

		requestBuilder = requestBuilder.url(url);

		// set the request method
		switch (method.toUpperCase()) {
		case GET:
			requestBuilder = requestBuilder.get();
			break;
		case POST:
			RequestBody requestBody = null;
			if (withRequestBody != null) {
				requestBody = withRequestBody;
			} else {
				requestBody = getRequestBodyToSend(contentType, content);
			}
			requestBuilder = requestBuilder.post(requestBody);
			break;
		case PUT:
			requestBody = getRequestBodyToSend(contentType, content);
			requestBuilder = requestBuilder.put(requestBody);
			break;
		case PATCH:
			requestBody = getRequestBodyToSend(contentType, content);
			requestBuilder = requestBuilder.patch(requestBody);
			break;
		case HEAD:
			requestBuilder = requestBuilder.head();
			break;
		case DELETE:
			requestBuilder = requestBuilder.delete();
			break;
		default:
			requestBuilder = requestBuilder.method(method, null);
		}

		requestBuilder = setHeaderProperties(requestBuilder, headerPropertys);

		return requestBuilder.build();
	}

	private RequestBody getRequestBodyToSend(String contentType, String content) {
		switch (contentType != null ? contentType.toUpperCase() : "") {
		case "JSON":
			return RequestBody.create(JSON, content);
		default:
			return RequestBody.create(null, new byte[0]);
		}
	}

	private Request.Builder setHeaderProperties(Request.Builder requestBuilder,
			Map<String, String> dynamicPropertys) {
		for (Entry<String, String> entry : dynamicPropertys.entrySet()) {
			requestBuilder = requestBuilder.addHeader(entry.getKey(),
					entry.getValue());
		}
		return requestBuilder;
	}

	@SuppressWarnings("deprecation")
	public String sendPowerbiHttp(String url) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", ConstantHelper.Authorization);
		return this.httpRequestWithContent(GET, url, headParams, null, null);
	}

	public String sendPowerbiHttp(String url, String access_key) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", "AppKey " + access_key);
		headParams.put("Content-Type", "application/json; charset=utf-8");
		return this.httpRequestWithContent(GET, url, headParams, null, null);
	}

	@SuppressWarnings("deprecation")
	public String sendPostHttp(String url) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", ConstantHelper.Authorization);
		return this.httpRequestWithContent(POST, url, headParams, null, null);
	}

	@SuppressWarnings("deprecation")
	public String sendPostHttp(String url, String body) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", ConstantHelper.Authorization);
		headParams.put("Content-Type", "application/json");
		return this.httpRequestWithContent(POST, url, headParams, null, body);
	}

	public String sendPatchHttp(String url, String body, String access_key) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", "AppKey " + access_key);
		headParams.put("Content-Type", "application/json");
		return this
				.httpRequestWithContent(PATCH, url, headParams, "JSON", body);
	}

	public String sendDeleteHttp(String url, String access_key) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", "AppKey " + access_key);
		headParams.put("Content-Type", "application/json");
		return this.httpRequestWithContent(DELETE, url, headParams, null, null);
	}

	public String httpPost(String url, String fileName, byte[] bytes, String access_key) {
		Map<String, String> headParams = new HashMap<String, String>();
		headParams.put("Authorization", "AppKey " + access_key);
		headParams.put("Content-Type", MULTIPART_FORM_DATA);
		RequestBody reqBody = null;
		reqBody = this.constructPart(fileName, bytes);
		return this.httpRequest(POST, url, headParams, null, null, reqBody);
	}

	private RequestBody constructPart(String fileName, byte[] bytes) {
		RequestBody requestBody = new MultipartBuilder()
				.type(MultipartBuilder.FORM)
				.addFormDataPart(
						"file",
						fileName,
						RequestBody.create(
								MediaType.parse(MULTIPART_FORM_DATA), bytes))
				.build();
		return requestBody;
	}

	public String replacePowerBiParam(String url, String collectionName,
			String wid) {
		if (StringUtils.isEmpty(collectionName)) {
			url = url.replace("{collectionName}", ConstantHelper.collectionName);
		} else {
			url = url.replace("{collectionName}", collectionName);
		}
		if (StringUtils.isEmpty(wid)) {
			url = url.replace("{workspaceID}", ConstantHelper.workspaceID);
		} else {
			url = url.replace("{workspaceID}", wid);
		}
		return url;
	}
}
